package net.goutalk.glcs.module.report.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.yulichang.toolkit.MPJWrappers;
import net.goutalk.glcs.common.enums.MenuType;
import net.goutalk.glcs.common.enums.YesOrNoEnum;
import net.goutalk.glcs.common.page.ConventPage;
import net.goutalk.glcs.common.page.PageOutput;
import net.goutalk.glcs.common.utils.VoToColumnUtil;
import net.goutalk.glcs.module.report.dto.AddReportReleaseDto;
import net.goutalk.glcs.module.report.dto.ReportReleasePageDto;
import net.goutalk.glcs.module.report.dto.UpdateReportReleaseDto;
import net.goutalk.glcs.module.report.entity.Report;
import net.goutalk.glcs.module.report.entity.ReportRelation;
import net.goutalk.glcs.module.report.mapper.ReportMapper;
import net.goutalk.glcs.module.report.mapper.ReportRelationMapper;
import net.goutalk.glcs.module.report.service.IReportRelationService;
import net.goutalk.glcs.module.report.vo.ReportReleaseInfoVo;
import net.goutalk.glcs.module.report.vo.ReportReleasePageVo;
import net.goutalk.glcs.module.system.entity.Menu;
import net.goutalk.glcs.module.system.mapper.MenuMapper;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 报表菜单关联关系表 服务实现类
 * </p>
 *
 * @author tanyujie
 * @since 2022-05-23
 */
@Service
@AllArgsConstructor
public class ReportRelationServiceImpl extends ServiceImpl<ReportRelationMapper, ReportRelation> implements IReportRelationService {

    private final ReportRelationMapper reportRelationMapper;

    private final ReportMapper reportMapper;

    private final MenuMapper menuMapper;

    @Override
    public PageOutput<ReportReleasePageVo> releasePage(ReportReleasePageDto dto) {
        IPage<ReportReleasePageVo> page = reportRelationMapper.selectJoinPage(ConventPage.getPage(dto), ReportReleasePageVo.class,
                MPJWrappers.<ReportRelation>lambdaJoin()
                        .like(StrUtil.isNotBlank(dto.getKeyword()), Report::getName, dto.getKeyword())
                        .select(ReportRelation::getId)
                        .select(ReportRelation.class,x -> VoToColumnUtil.fieldsToColumns(ReportRelation.class).contains(x.getProperty()))
                        .selectAs(Menu::getTitle, ReportReleasePageVo::getTitle)
                        .selectAs(Menu::getCode, ReportReleasePageVo::getCode)
                        .selectAs(Menu::getParentId, ReportReleasePageVo::getParentId)
                        .selectAs(Report::getName, ReportReleasePageVo::getReportName)
                        .selectAs(Menu::getRemark, ReportReleasePageVo::getRemark)
                        .leftJoin(Menu.class, Menu::getId, ReportRelation::getMenuId)
                        .leftJoin(Report.class, Report::getId, ReportRelation::getReportId)
                        .orderByDesc(StrUtil.isBlank(dto.getField()), Menu::getCreateDate));
        Set<Long> parentIdList = page.getRecords().stream().filter(vo -> vo.getParentId() != null && vo.getParentId() != 0L).map(ReportReleasePageVo::getParentId).collect(Collectors.toSet());
        if (CollectionUtils.isNotEmpty(parentIdList)) {
            // 设置parentName
            List<Menu> parentMenuList = menuMapper.selectList(Wrappers.<Menu>query().lambda()
                    .select(Menu::getId, Menu::getTitle).in(Menu::getId, parentIdList));
            for (ReportReleasePageVo pageVo : page.getRecords()) {
                for (Menu parentMenu : parentMenuList) {
                    if (parentMenu.getId().equals(pageVo.getParentId())) {
                        pageVo.setParentName(parentMenu.getTitle());
                    }
                }
            }
        }
        return ConventPage.getPageOutput(page);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean add(AddReportReleaseDto dto) {
        Menu menu = BeanUtil.toBean(dto, Menu.class);
        setMenuInfo(menu);
        menu.setName(dto.getTitle());
        Report report = reportMapper.selectOne(Wrappers.<Report>query().lambda().select(Report::getName).eq(Report::getId, dto.getReportId()));
        if (report != null) {
            String reportName = report.getName();
            menu.setPath("/report/" + reportName.substring(0, reportName.indexOf(".")));
        }
        menuMapper.insert(menu);
        ReportRelation relation = new ReportRelation();
        relation.setMenuId(menu.getId());
        relation.setReportId(dto.getReportId());
        return this.save(relation);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean update(UpdateReportReleaseDto dto) {

        Menu menu = BeanUtil.toBean(dto, Menu.class);
        menu.setId(dto.getMenuId());
        setMenuInfo(menu);
        menu.setName(dto.getTitle());
        Report report = reportMapper.selectOne(Wrappers.<Report>query().lambda().select(Report::getName).eq(Report::getId, dto.getReportId()));
        if (report != null) {
            String reportName = report.getName();
            menu.setPath("/report/" + reportName.substring(0, reportName.indexOf(".")));
        }
        menuMapper.updateById(menu);
        ReportRelation relation = new ReportRelation();
        relation.setId(dto.getId());
        relation.setMenuId(dto.getMenuId());
        relation.setReportId(dto.getReportId());
        return this.updateById(relation);
    }

    @Override
    public ReportReleaseInfoVo info(Long id) {
        ReportRelation reportRelation = this.getById(id);
        ReportReleaseInfoVo infoVo = BeanUtil.toBean(reportRelation, ReportReleaseInfoVo.class);
        Menu menu = menuMapper.selectById(reportRelation.getMenuId());
        BeanUtil.copyProperties(menu, infoVo, true);
        return infoVo;
    }

    private void setMenuInfo(Menu menu) {
        menu.setComponentType(YesOrNoEnum.YES.getCode());
        menu.setMenuType(MenuType.FUNCTION.getCode());
        menu.setComponent("report/template/index");
        menu.setDisplay(YesOrNoEnum.YES.getCode());
        menu.setAllowDelete(YesOrNoEnum.YES.getCode());
        menu.setAllowModify(YesOrNoEnum.YES.getCode());
        menu.setOutLink(YesOrNoEnum.NO.getCode());
        menu.setKeepAlive(YesOrNoEnum.NO.getCode());
    }
}
